﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using PivotData;
using PivotWebsite.Controllers;
using System;
using System.Linq;
using System.Web.Http;

namespace PivotWebsite.Tests.Controllers
{
    [TestClass]
    public class FacetsControllerTest
    {
        [TestInitialize]
        public void TestReset()
        {
            Utils.TestInit();
        }

        [TestCleanup]
        public void TestCleanup()
        {
            Utils.TestFinalize();
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestGetBadCollectionId()
        {
            var fc = new FacetsController();
            fc.GetFacets(1, 1);
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestGetBadImageId()
        {
            var fc = new FacetsController();
            var tc = new CollectionsController();
            var p = tc.PutCollection("freak");
            fc.GetFacets(p.Id, 1);
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutBadCollectionId()
        {
            var fc = new FacetsController();
            fc.PutFacet(1, 1, "dude", "me");
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutBadImageId()
        {
            var fc = new FacetsController();
            var tc = new CollectionsController();
            var p = tc.PutCollection("freak");
            fc.PutFacet(p.Id, 1, "dude", "me");
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsBadCollectionId()
        {
            var fc = new FacetsController();
            fc.PutFacet(1, 1, new FacetString[] { new FacetString() { Name = "dude", Value = "fork" } });
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsBadImageId()
        {
            var fc = new FacetsController();
            var tc = new CollectionsController();
            var p = tc.PutCollection("freak");
            fc.PutFacet(p.Id, 1, new FacetString[] { new FacetString() { Name = "dude", Value = "fork" } });
        }

        public Tuple<CollectionInfo, ImageInfo> InitImage(int numImages = 1)
        {
            var tc = new CollectionsController();
            var info = tc.PutCollection("dude");
            var ic = new ImagesController();
            ImageInfo img = null;
            for (int i = 0; i < numImages; i++)
            {
                var inputData = Utils.GetPng();
                img = ic.PutImage(info.Id, string.Format("fork{0}", i), inputData);
            }
            return Tuple.Create(info, img);
        }

        [TestMethod]
        [DeploymentItem("test.png")]
        public void TestNoFacets()
        {
            var info = InitImage();
            var fc = new FacetsController();
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(0, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        [DeploymentItem("test.png")]
        public void TestGetPutOneStringFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "first", "me");
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
            Assert.AreEqual("first", facets[0].Name, "Name of facet");
            Assert.AreEqual("me", (facets[0] as FacetString).Value, "value of string facet");
        }

        #region NullTests

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutNullNameStringFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, null, "me");
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutNullValueStringFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "dude", null);
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutNullNameDateFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, null, DateTime.Now);
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutNullValueDateFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "hi", null);
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutNullNameNumberFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, null, 5.5);
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutNullNameUriFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, null, "hi", new Uri("http://www.nytimes.com"));
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutNullLinkStringUriFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "fork", null, new Uri("http://www.nytimes.com"));
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutNullUriUriFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "fork", "hi", null);
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsNullNameFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetString() { Name = null, Value = "hi" } });
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsNullNameStringFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetString() { Name = null, Value = "me" } });
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsNullValueStringFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetString() { Name = "dude", Value = null } });
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsNullNameDateFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetDateTime() { Name = null, Date = DateTime.Now } });
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsNullNameNumberFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetNumber() { Name = null, Number = 5.5 } });
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsNullNameUriFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetUri() { Name = null, LinkString = "hi", URI = new Uri("http://www.nytimes.com") } });
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsNullLinkStringUriFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetUri() { Name = "fork", LinkString = null, URI = new Uri("http://www.nytimes.com") } });
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutsNullUriUriFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetUri() { Name = "fork", LinkString = "hi", URI = null } });
        }

        [TestMethod]
        [ExpectedException(typeof(HttpResponseException))]
        public void TestPutssNullNameFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetString() { Name = null, Value = "hi" } });
        }

        #endregion

        [TestMethod]
        [DeploymentItem("test.png")]
        public void TestGetPutOneNumberFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "first", 1.2);
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
            Assert.AreEqual("first", facets[0].Name, "Name of facet");
            Assert.AreEqual(1.2, (facets[0] as FacetNumber).Number, "value of string facet");
        }

        [TestMethod]
        [DeploymentItem("test.png")]
        public void TestGetPutOneIntegerFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "first", 1);
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
            Assert.AreEqual("first", facets[0].Name, "Name of facet");
            Assert.AreEqual(1, (int)(facets[0] as FacetNumber).Number, "value of string facet");
        }

        [TestMethod]
        [DeploymentItem("test.png")]
        public void TestGetPutOneDateFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            var dt = DateTime.Now;
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "first", dt);
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
            Assert.AreEqual("first", facets[0].Name, "Name of facet");
            Assert.AreEqual(dt, (facets[0] as FacetDateTime).Date, "value of string facet");
        }

        [TestMethod]
        [DeploymentItem("test.png")]
        public void TestGetPutOneUriFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "first", "smooth", new Uri("http://www.nytimes.com"));
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
            Assert.AreEqual("first", facets[0].Name, "Name of facet");
            Assert.AreEqual("smooth", (facets[0] as FacetUri).LinkString, "value of string facet");
            Assert.AreEqual("http://www.nytimes.com/", (facets[0] as FacetUri).URI.AbsoluteUri, "value of string facet");
        }

        [TestMethod]
        [DeploymentItem("test.png")]
        public void TestGetPutTwoStringFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "first", "me");
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "second", "me");
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(2, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        [DeploymentItem("test.png")]
        public void TestGetPutTwoSameStringFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "first", "me");
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "first", "me");
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        public void TestPutsNoNewFacets()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { });
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.AreEqual(0, facets.Length, "Expected no factets");
        }

        [TestMethod]
        public void TestPutsNew1Facets()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "first", Value = "me" } });
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
            Assert.AreEqual("first", facets[0].Name, "Name of facet");
            Assert.AreEqual("me", (facets[0] as FacetString).Value, "value of string facet");
        }

        [TestMethod]
        public void TestPutsNew2Facets()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "first", Value = "me" }, new FacetString() { Name = "second", Value = "me2" } });
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(2, facets.Length, "Length of facets is nothing");
            Assert.IsTrue(facets.Where(f => f.Name == "first").Cast<FacetString>().Where(f => f.Value == "me").Any(), "First facet missing");
            Assert.IsTrue(facets.Where(f => f.Name == "second").Cast<FacetString>().Where(f => f.Value == "me2").Any(), "First facet missing");
        }

        [TestMethod]
        public void TestPutsNew2FacetsWithSameName()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "first", Value = "me" }, new FacetString() { Name = "first", Value = "me2" } });
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(2, facets.Length, "Length of facets is nothing");
            Assert.IsTrue(facets.Where(f => f.Name == "first").Cast<FacetString>().Where(f => f.Value == "me").Any(), "First facet missing");
            Assert.IsTrue(facets.Where(f => f.Name == "first").Cast<FacetString>().Where(f => f.Value == "me2").Any(), "First facet missing");
        }

        [TestMethod]
        public void TestPutsNewFactsSame()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "first", Value = "me" }, new FacetString() { Name = "first", Value = "me" } });
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        public void TestPutsNamedImageNewFacet()
        {
            var info = InitImage();
            var fc = new FacetsController();
            var num = fc.PutFacet(info.Item1.Id, info.Item2.Name, new FacetString[] { new FacetString() { Name = "first", Value = "me" }, new FacetString() { Name = "first", Value = "me" } });
            Assert.AreEqual(1, num, "# of images inserted");
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        public void TestPutsNamedImageNewFacetWithRegEx()
        {
            var info = InitImage();
            var fc = new FacetsController();
            var num = fc.PutFacet(info.Item1.Id, "f.*", new FacetString[] { new FacetString() { Name = "first", Value = "me" }, new FacetString() { Name = "first", Value = "me" } });
            Assert.AreEqual(1, num, "# of images inserted");
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        public void TestPutsNamedImageNewFacet2WithRegEx()
        {
            var info = InitImage(2);
            var fc = new FacetsController();
            var num = fc.PutFacet(info.Item1.Id, "f.*", new FacetString[] { new FacetString() { Name = "first", Value = "me" }, new FacetString() { Name = "first", Value = "me" } });
            Assert.AreEqual(2, num, "# of images inserted");
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.IsNotNull(facets, "facets should not be null");
            Assert.AreEqual(1, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        public void TestPutsNewFactsSameTwice()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "first", Value = "me" }, new FacetString() { Name = "first", Value = "me" } });
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "sec", Value = "me" }, new FacetString() { Name = "sec", Value = "me" } });
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.AreEqual(2, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        public void TestPutsNewFactsReplace()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "first", Value = "me" }, new FacetString() { Name = "first", Value = "two" } }, true);
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "first", Value = "trhee" }, new FacetString() { Name = "first", Value = "four" } }, true);
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.AreEqual(2, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        public void TestPutsNewFactsNoReplace()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "first", Value = "me" }, new FacetString() { Name = "first", Value = "two" } }, false);
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetString[] { new FacetString() { Name = "first", Value = "trhee" }, new FacetString() { Name = "first", Value = "four" } }, false);
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.AreEqual(4, facets.Length, "Length of facets is nothing");
        }

        [TestMethod]
        public void TestFacesReplaceLotsOfDates()
        {
            var info = InitImage();
            var fc = new FacetsController();
            var n = DateTime.Now;
            foreach (var item in Enumerable.Range(0, 20))
            {
                n = n + TimeSpan.FromSeconds(1);
                fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetDateTime() { Name = "first", Date = n } });
            }
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.AreEqual(20, facets.Length, "Number of facets");
            fc.PutFacet(info.Item1.Id, info.Item2.Id, new FacetAbsBase[] { new FacetDateTime() { Name = "first", Date = DateTime.Now } }, true);
            facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.AreEqual(1, facets.Length, "Number of facets");
        }

        [TestMethod]
        public void TestPutsOneFacetOfEach()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id,
                new FacetAbsBase[] {
                    new FacetString() { Name = "first", Value = "me" },
                    new FacetNumber() { Name = "second", Number = 10.5 },
                    new FacetDateTime() {Name = "third", Date = DateTime.Now},
                    new FacetUri() {Name="fourth", LinkString = "smooth", URI=new Uri("http://www.nytimes.com")},
                });
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.AreEqual(4, facets.Length);
        }

        [TestMethod]
        public void TestPutsOneFacetOfEachReplace()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id,
                new FacetAbsBase[] {
                    new FacetString() { Name = "first", Value = "me" },
                    new FacetNumber() { Name = "second", Number = 10.5 },
                    new FacetDateTime() {Name = "third", Date = DateTime.Now},
                    new FacetUri() {Name="fourth", LinkString = "smooth", URI=new Uri("http://www.nytimes.com")},
                });
            fc.PutFacet(info.Item1.Id, info.Item2.Id,
                new FacetAbsBase[] {
                    new FacetString() { Name = "first", Value = "me" },
                    new FacetNumber() { Name = "second", Number = 10.5 },
                    new FacetDateTime() {Name = "third", Date = DateTime.Now},
                    new FacetUri() {Name="fourth", LinkString = "smooth", URI=new Uri("http://www.nytimes.com")},
                }, true);
            var facets = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.AreEqual(4, facets.Length);
        }

        [TestMethod]
        [DeploymentItem("test.png")]
        public void TestDeleteAllFacets()
        {
            var info = InitImage();
            var fc = new FacetsController();
            fc.PutFacet(info.Item1.Id, info.Item2.Id, "first", "me");
            fc.DeleteFacet(info.Item1.Id, info.Item2.Id);
            var r = fc.GetFacets(info.Item1.Id, info.Item2.Id);
            Assert.AreEqual(0, r.Length);
        }
    }
}
